#ifndef _SDB_MEM_H_
#define _SDB_MEM_H_

/*
 * Copyright (c) 2009 Tom Bradford <spinneretdb.org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * Implements a concept called Memory Chains (for lack of a better
 * term).  Memory Chains allow a developer to manage a group of memory
 * allocations in a more atomic manner, and with greater flexibility.
 * The Chains support reference counted, explicit, and transactional
 * deallocation depending on the developer's needs.
 *
 * Note: These functions are NOT thread-safe.  You must manage your
 * own mutexes if you plan on safely threading the reference counting
 * features.
 */

#include <stdlib.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus


/** Incomplete type for Memory Chain instances */
typedef struct sdb_mem_t sdb_mem_t;

/** Implementation type for Memory Function Table instances */
typedef struct {
    void* (*mallocFunction)(size_t size);
    void* (*reallocFunction)(void* ptr, size_t size);
    void* (*memsetFunction)(void* ptr, int c, size_t len);
    void (*freeFunction)(void* ptr);
} sdb_mem_functions_t;

/** Function type for Reference disposal callbacks */
typedef void sdb_ptr_disposal_t(void* ptr);

/** Create a Memory Chain instance with optional parent */
sdb_mem_t* sdb_mem_new(sdb_mem_t* parentMem);
        
/** Allocates a block and returns its associated Reference */
void* sdb_mem_malloc(sdb_mem_t* mem, size_t size);

/** Allocates an array and returns its associated Reference */
void* sdb_mem_calloc(sdb_mem_t* mem, size_t count, size_t size);

/** Sets whether or not to clear allocated memory */
void sdb_mem_setClearMemory(sdb_mem_t* mem, bool clearMemory);

/** Returns whether or not to clear allocated memory */
bool sdb_mem_isClearMemory(sdb_mem_t* mem);

/** Sets the memory-related functions for the Memory Chain */
void sdb_mem_setMemoryFunctions(sdb_mem_t* mem,
                                sdb_mem_functions_t* functions);

/** Returns the memory-related functions for the Memory Chain */
sdb_mem_functions_t* sdb_mem_getMemoryFunctions(sdb_mem_t* mem);

/** Sets the disposal function associated with the Reference */
void sdb_ptr_setDisposalFunction(void* ptr,
                                 sdb_ptr_disposal_t* disposalFunction);

/** Returns the disposal function associated with the Reference */
sdb_ptr_disposal_t* sdb_ptr_getDisposalFunction(void* ptr);

/**
 * Retains the specified Reference (increases its reference count).
 * Will accept a NULL pointer, resulting in a No-Op.
 */
void* sdb_ptr_retain(void* ptr);

/**
 * Releases the specified Pointer (decreases its reference count)
 * Will accept a NULL pointer, resulting in a No-Op.
 */
void sdb_ptr_release(void* ptr);

/** Resizes a block of memory */
void* sdb_ptr_realloc(void* ptr, size_t size);

/** Explicitly frees a Reference's memory (ignoring reference count) */
void sdb_ptr_free(void* ptr);

/** Returns the size of a Reference's memory */
size_t sdb_ptr_getSize(void* ptr);

/** Returns the Reference's associated Memory Chain instance */
sdb_mem_t* sdb_ptr_getMem(void* ptr);


#ifdef __cplusplus
}
#endif // __cplusplus

#endif // _SDB_MEM_H_
